﻿using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Portal.Logic.Creators;
using Portal.Logic.Tests.Units;
using Portal.Model;
using Portal.Repository;
using Rhino.Mocks;
using Portal.Logic.Services;

namespace Portal.Logic.Services.Tests.Units
{
	[TestClass]
	public class UserInfoServiceTests : BaseTests
	{
		private IContactInfoService _contactInfoService;
		private IUserInfoCreator _cretor;
		private IPortalUnitOfWorkProvider _unitOfWorks;
		private IUserService _userService;

		protected override void InitializeTest()
		{
			_contactInfoService = Mocks.DynamicMock<IContactInfoService>();
			_cretor = Mocks.DynamicMock<IUserInfoCreator>();
			_unitOfWorks = Mocks.DynamicMock<IPortalUnitOfWorkProvider>();
			_userService = Mocks.DynamicMock<IUserService>();
		}

		#region GetBy

		[TestMethod]
		public void GetBy_UserIsNull_ReturnsNull()
		{
			Mocks.ReplayAll();

			var service = GetService();
			var result = service.GetBy(null);

			result.Should().BeNull();
		}

		[TestMethod]
		public void GetBy_UserInfoIsNull_ReturnsNull()
		{
			var user = Mocks.Stub<IUser>();
			Expect.Call(_cretor.From(user)).Return(null);
			Mocks.ReplayAll();

			var service = GetService();
			var result = service.GetBy(user);

			result.Should().BeNull();
		}

		[TestMethod]
		public void GetBy_InfosCountIsZero_ReturnsUserInfo()
		{
			var user = Mocks.Stub<IUser>();
			SetupResult.For(user.Login).Return("login");

			var info = Mocks.Stub<IUserInfo>();
			Expect.Call(_cretor.From(user)).Return(info);

			Expect.Call(_contactInfoService.GetUserContactInfosBy(user.Login)).Return(null);

			Mocks.ReplayAll();

			var service = GetService();
			var result = service.GetBy(user);

			result.Should().Be(info);
		}

		[TestMethod]
		public void GetBy_PrimaryPhoneIsProvided_ReturnsUserInfo()
		{
			var login = "login";
			var user = Mocks.Stub<IUser>();
			SetupResult.For(user.Login).Return(login);

			var info = Mocks.Stub<IUserInfo>();
			Expect.Call(_cretor.From(user)).Return(info);

			var contactInfo = Mocks.Stub<IContactInfo>();
			contactInfo.IsDefault = true;
			contactInfo.Type = ContactInfoType.Phone;
			contactInfo.Value = "value";

			var infos = new IContactInfo[] { contactInfo };

			Expect.Call(_contactInfoService.GetUserContactInfosBy(login)).Return(infos);

			Mocks.ReplayAll();

			var service = GetService();
			var result = service.GetBy(user);

			result.Should().Be(info);
			result.PrimaryPhone.Should().Be(contactInfo);
		}

		[TestMethod]
		public void GetBy_SecondaryPhoneIsProvided_ReturnsUserInfo()
		{
			var login = "login";
			var user = Mocks.Stub<IUser>();
			SetupResult.For(user.Login).Return(login);

			var info = Mocks.Stub<IUserInfo>();
			Expect.Call(_cretor.From(user)).Return(info);

			var contactInfo = Mocks.Stub<IContactInfo>();
			contactInfo.IsDefault = false;
			contactInfo.Type = ContactInfoType.Phone;
			contactInfo.Value = "value";

			var infos = new IContactInfo[] { contactInfo };

			Expect.Call(_contactInfoService.GetUserContactInfosBy(login)).Return(infos);

			Mocks.ReplayAll();

			var service = GetService();
			var result = service.GetBy(user);

			result.Should().Be(info);
			result.SecondaryPhone.Should().Be(contactInfo);
		}

		[TestMethod]
		public void GetBy_PrimaryEmailIsProvided_ReturnsUserInfo()
		{
			var login = "login";
			var user = Mocks.Stub<IUser>();
			SetupResult.For(user.Login).Return(login);

			var info = Mocks.Stub<IUserInfo>();
			Expect.Call(_cretor.From(user)).Return(info);

			var contactInfo = Mocks.Stub<IContactInfo>();
			contactInfo.IsDefault = true;
			contactInfo.Type = ContactInfoType.Email;
			contactInfo.Value = "value";

			var infos = new IContactInfo[] { contactInfo };

			Expect.Call(_contactInfoService.GetUserContactInfosBy(login)).Return(infos);

			Mocks.ReplayAll();

			var service = GetService();
			var result = service.GetBy(user);

			result.Should().Be(info);
			result.PrimaryEmail.Should().Be(contactInfo);
		}

		[TestMethod]
		public void GetBy_SecondaryEmailIsProvided_ReturnsUserInfo()
		{
			var login = "login";
			var user = Mocks.Stub<IUser>();
			SetupResult.For(user.Login).Return(login);

			var info = Mocks.Stub<IUserInfo>();
			Expect.Call(_cretor.From(user)).Return(info);

			var contactInfo = Mocks.Stub<IContactInfo>();
			contactInfo.IsDefault = false;
			contactInfo.Type = ContactInfoType.Email;
			contactInfo.Value = "value";

			var infos = new IContactInfo[] { contactInfo };

			Expect.Call(_contactInfoService.GetUserContactInfosBy(login)).Return(infos);

			Mocks.ReplayAll();

			var service = GetService();
			var result = service.GetBy(user);

			result.Should().Be(info);
			result.SecondaryEmail.Should().Be(contactInfo);
		}

		#endregion GetBy

		#region IsValid
		[TestMethod()]
		public void IsValid_UserInfoIsNull_ReturnsFalse()
		{
			Mocks.ReplayAll();

			var service = GetService();
			var result = service.IsValid(null);

			result.Should().BeFalse();
		}

		[TestMethod()]
		public void IsValid_UserIsNotValid_ReturnsFalse()
		{
			var info = Mocks.Stub<IUserInfo>();
			Expect.Call(_userService.IsValid(null)).IgnoreArguments().Return(false);
			Mocks.ReplayAll();

			var service = GetService();
			var result = service.IsValid(info);

			result.Should().BeFalse();
		}

		[TestMethod()]
		public void IsValid_PrimaryEmailIsNotValid_ReturnsFalse()
		{
			var info = Mocks.Stub<IUserInfo>();
			var email = Mocks.DynamicMock<IContactInfo>();
			var phone = Mocks.DynamicMock<IContactInfo>();
			info.PrimaryEmail = email;
			info.PrimaryPhone = phone;

			Expect.Call(_userService.IsValid(null)).IgnoreArguments().Return(true);
			Expect.Call(_contactInfoService.IsValid(email)).Return(false);
			Expect.Call(_contactInfoService.IsValid(phone)).Return(true);
			Mocks.ReplayAll();

			var service = GetService();
			var result = service.IsValid(info);

			result.Should().BeFalse();
		}

		[TestMethod()]
		public void IsValid_PrimaryPhoneIsNotValid_ReturnsFalse()
		{
			var info = Mocks.Stub<IUserInfo>();
			var email = Mocks.DynamicMock<IContactInfo>();
			var phone = Mocks.DynamicMock<IContactInfo>();
			info.PrimaryEmail = email;
			info.PrimaryPhone = phone;

			Expect.Call(_userService.IsValid(null)).IgnoreArguments().Return(true);
			Expect.Call(_contactInfoService.IsValid(email)).Return(true);
			Expect.Call(_contactInfoService.IsValid(phone)).Return(false);
			Mocks.ReplayAll();

			var service = GetService();
			var result = service.IsValid(info);

			result.Should().BeFalse();
		}

		[TestMethod()]
		public void IsValid_UserInfoIsValid_ReturnsTrue()
		{
			var info = Mocks.Stub<IUserInfo>();
			var email = Mocks.DynamicMock<IContactInfo>();
			var phone = Mocks.DynamicMock<IContactInfo>();
			info.PrimaryEmail = email;
			info.PrimaryPhone = phone;

			Expect.Call(_userService.IsValid(null)).IgnoreArguments().Return(true);
			Expect.Call(_contactInfoService.IsValid(email)).Return(true);
			Expect.Call(_contactInfoService.IsValid(phone)).Return(true);
			Mocks.ReplayAll();

			var service = GetService();
			var result = service.IsValid(info);

			result.Should().BeTrue();
		}
		#endregion

		private UserInfoService GetService()
		{
			return new UserInfoService(_unitOfWorks, _userService, _contactInfoService, _cretor);
		}


	}
}